/* String_to_function
————————————————————————————————————————————————————————————
Класс обеспечивает возможность вызова функций по текстовой
строке. Основной класс Command_Parser, для хранения описаний
функций используются классы произвоздные от Function. 

Публичные методы основного класса:

Register — создает новое описание типа указанного как 
параметр шаблона.
Update — обновляет значения указателей указанной функции.
Remove — удаляет описание функции.
Call — вызов функции.

Пространство имен stf.
————————————————————————————————————————————————————————————
*/

#ifndef string_to_function_h
#define string_to_function_h


#include <map>
#include <string>
#include <vector>

namespace stf {
	// Типы
	//------------------------------------------------------------
	enum Token_Type {
		IP_TOKEN_WORD = 's',
		IP_TOKEN_INT = 'i',
		IP_TOKEN_CHAR = 'c',
		IP_TOKEN_FLOAT = 'f',
		IP_TOKEN_SPECIAL_SYMBOL
	};

	enum Symbol_Type {
		IP_SYMBOL_NUMBER = 0,
		IP_SYMBOL_CHAR,
		IP_SYMBOL_FLOAT_DIVIDER,
		IP_SYMBOL_BREAKER
	};

	// Token
	//------------------------------------------------------------
	struct Token {
		Token_Type  type;
		std::string value;
	};

	/* Function
	//------------------------------------------------------------
	Базовый класс, отвечает за хранение указателя на функцию,
	проверку аргументов и вызов функции. 

	Возможно использование шаблона несоответствующего вызываемой
	функции, в этом случае вызов произойдет, но в аргументах 
	функции будут мусорные значения.

	Класс не проводит проверку указателя на объект, только
	проверяет его отличие от nullptr.
	//------------------------------------------------------------
	*/
	class Function {
	protected:
		int   name_tokens_count;
		bool  pass_object_ptr;
		void* func_ptr;
		void* object_ptr;

	public:	
		void Set( const std::string&, const int&, void*, void* =nullptr );
		int  CheckArguments( const std::vector<Token*>&, const std::string );
		int  TypesAreCompatible( const char&, const Token& );
		int  NameWordsCount();

		virtual void Call( const std::vector<Token*>& ) =0;
	};
	
	// Шаблоны вызываемых функций
	//------------------------------------------------------------
	class NoArgs: public Function {
	public:
		void Call( const std::vector<Token*>& );
	};

	class I: public Function {
	public:
		void Call( const std::vector<Token*>& );
	};

	class F: public Function {
	public:
		void Call( const std::vector<Token*>& );
	};

	class S: public Function {
	public:
		void Call( const std::vector<Token*>& );
	};

	class C: public Function {
	public:
		void Call( const std::vector<Token*>& );
	};

	class FFF: public Function {
	public:
		void Call( const std::vector<Token*>& );
	};

	class IS: public Function {
	public:
		void Call( const const std::vector<Token*>& );
	};

	class SI: public Function {
	public:
		void Call( const std::vector<Token*>& );
	};

	// Input parser
	//------------------------------------------------------------
	class String_To_Function {
	protected:
		std::map<int, Function*> functions;
		Symbol_Type symbols[255];
		std::hash<std::string> H;

	public:
		String_To_Function();
		
		template<class Type>
		int Register( const std::string name, void* func_ptr, void* object_ptr = nullptr ) {
			if( !name.size() || func_ptr == nullptr )
				return 0;

			int name_hash = H( name );

			if( functions.find( name_hash ) != functions.end() )
				return 0;

			Type* new_function = new Type;
			int name_words_count = CountWords(name);
			new_function->Set( name, name_words_count, func_ptr, object_ptr );
			functions[name_hash] = new_function;

			return 1;
		}

		int  Update( const std::string, void*, void* = nullptr );
		void Remove( const std::string );
		int  Call( const std::string );

		void		SetSymbolType( const char, const Symbol_Type );
		Symbol_Type GetSymbolType( const char );

	protected:
		int		   CountWords( const std::string& );
		void	   TokenizeString( const std::string&, std::vector<Token*>& );	
		Token*	   CreateToken( const std::string& );								
		Token_Type GetTokenType( const std::string& );
		Function*  FindFunction( const std::vector<Token*>& );				
		void	   ClearTokens( std::vector<Token*>& );
	};
};
#endif //string-to-function_h